/*!
 Temelia - Sorting algorithms samples.

 Copyright (C) 2008 Ceata (http://ceata.org/proiecte/temelia).

 @author Dascalu Laurentiu

 This program is free software; you can redistribute it and
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 3
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "include/samples.h"
#include <time.h>
#include <temelia/sort.h>

static long int test[] =
{ 10, 20, 400, 1000, 2000, 5000, 100000, 10000000 };

static void generic_sort(int k, void generic_sort_algorithm(void *data,
		int size, void *key_at(void *data, int index), void set_key_at(
				void *data, int index, void *new_value), int compare(void *x,
				void *y, void *context), void *context), int compare(void *x,
		void *y, void *context), void *context, char *generic_sort_name)
{
	clock_t start, stop;
	int **data;
	int i;

	for (i = 0; i < k; i++)
	{
		data = int_array_new(test[i], 1000);
		start = clock();
		generic_sort_algorithm(data, test[i], my_key_at, my_set_key_at,
				compare, context);
		stop = clock();
		if (is_sorted(data, test[i], my_key_at, compare, context) == 1)
			PRINT("%s test %ld : %lf\n", generic_sort_name, test[i],
					(double) (stop - start) / CLOCKS_PER_SEC);
		else
			PRINT("%s error at test %d!\n", generic_sort_name, i);
		int_array_delete(data, test[i]);
	}
}

static void test_bubble_sort(int k)
{
	generic_sort(k, bubble_sort, int_compare, NULL, "Bubble sort");
}

static void test_insertion_sort(int k)
{
	generic_sort(k, insertion_sort, int_compare, NULL, "Insertion sort");
}

static void test_merge_sort(int k)
{
	generic_sort(k, merge_sort, int_compare, NULL, "Merge sort");
}

static void test_quick_sort(int k)
{
	generic_sort(k, quick_sort, int_compare, NULL, "Quick sort");
}

static void test_selection_sort(int k)
{
	generic_sort(k, selection_sort, int_compare, NULL, "Selection sort");
}

static void test_shell_sort(int k)
{
	generic_sort(k, shell_sort, int_compare, NULL, "Shell sort");
}

static void test_heap_sort(int k)
{
	generic_sort(k, heap_sort, int_compare, NULL, "Heap sort");
}

static void test_gnome_sort(int k)
{
	generic_sort(k, gnome_sort, int_compare, NULL, "Gnome sort");
}

static void test_cocktail_sort(int k)
{
	generic_sort(k, cocktail_sort, int_compare, NULL, "Cocktail sort");
}

static int radix_compare(void *x, void *y, void *context)
{
	return (int) ((unsigned long) x - (unsigned long) y);
}

static void test_radix_sort(int k)
{
	clock_t start, stop;
	int *data;
	int i, j;

	for (i = 0; i < k; i++)
	{
		data = (int *) malloc(test[i] * sizeof(int));

		for (j = 0; j < test[i]; j++)
			data[j] = rand();

		start = clock();
		radix_sort(data, test[i], 10);
		stop = clock();
		if (is_sorted(data, test[i], my_key_at, radix_compare, NULL))
			PRINT("Radix sort test %ld : %lf\n", test[i], (double) (stop
							- start) / CLOCKS_PER_SEC);
		else
			PRINT("Radix sort error at test %d!\n", i);
		free(data);
	}
}

static void test_number_sort(int k)
{
	clock_t start, stop;
	unsigned int *data;
	int i, j, max_value;

	for (i = 0; i < k; i++)
	{
		data = (unsigned int *) malloc(test[i] * sizeof(unsigned int));

		if (test[i] >= 256)
			max_value = 256;
		else
			max_value = test[i];

		for (j = 0; j < test[i]; j++)
			data[j] = rand() % max_value;

		start = clock();
		number_sort(data, test[i], max_value);
		stop = clock();
		if (is_sorted(data, test[i], my_key_at, radix_compare, NULL))
			PRINT("Number sort test %ld : %lf\n", test[i], (double) (stop
							- start) / CLOCKS_PER_SEC);
		else
			PRINT("Number sort error at test %d!\n", i);
		free(data);
	}
}

void run_sort_samples()
{
	test_bubble_sort(4);
	test_merge_sort(4);
	test_insertion_sort(3);
	test_quick_sort(7);
	test_selection_sort(4);
	test_shell_sort(7);
	test_heap_sort(7);
	test_gnome_sort(2);
	test_cocktail_sort(3);
	test_radix_sort(7);
	test_number_sort(8);
}
